package cn.glc.daily.life.common.utils;

import cn.glc.daily.life.model.vo.jwt.auth.JwtUserDetailVo;
import com.alibaba.fastjson.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;

import java.io.UnsupportedEncodingException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.Map;

/**
 * jwt token 生成,校验
 *
 * @author simon
 * @date 2020/7/7 13:46
 * @copyright:
 * @modifier
 * @motto a no talent, people who have to study hard
 */
@Slf4j
public class JwtUtils {

    /**
     * 过期时间5分钟
     */
    private static final long DEFAULT_EXPIRE_TIME = 1800;
    private static final Map<Object, Exception> errors = Maps.newConcurrentMap();

    /**
     * 校验token是否正确(只保存最近的一次错误信息)
     *
     * @param token  密钥
     * @param secret 用户的密码
     * @return 是否正确
     */
    public static boolean verify(String token, String jwt, String secret) {
        try {
            errors.remove(jwt);
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim("jwt", jwt)
                    .build();
            verifier.verify(token);
            return true;
        } catch (UnsupportedEncodingException | SignatureVerificationException e) {
            errors.putIfAbsent(jwt, e);
        }
        return false;
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户名
     */
    public static JwtUserDetailVo getUserInfo(String token) {
        try {
            DecodedJWT decodedJWT = JWT.decode(token);
            String jwtPayload = decodedJWT.getClaim("jwt").as(String.class);
            return JSON.parseObject(jwtPayload, JwtUserDetailVo.class);
        } catch (JWTDecodeException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 生成签名,有效期 {@link JwtUtils DEFAULT_EXPIRE_TIME}
     *
     * @param jwt    uid 唯一标识
     * @param secret 凭证(密码)
     * @return 加密的token
     */
    public static String sign(String jwt, String secret) {
        try {
            LocalDateTime localDateTime = LocalDateTime.now().plusSeconds(DEFAULT_EXPIRE_TIME);
            Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
            Algorithm algorithm = Algorithm.HMAC256(secret);
            return JWT.create()
                    .withClaim("jwt", jwt)
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static Exception getErrors(String jwt) {
        if (errors.containsKey(jwt)) {
            return errors.getOrDefault(jwt, null);
        }
        return null;
    }
}
